package com.bkhech.home.practice.javacore.fileupload;

import lombok.extern.slf4j.Slf4j;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URLEncoder;

import static java.nio.charset.StandardCharsets.UTF_8;

/**
 * FileDownloadUtils
 * 文件下载：多线程分段下载，并且支持断点续传
 *
 * @author guowm
 * @date 2024/7/3
 */
@Slf4j
public class FileDownloadUtils {

    /**
     * 文件下载
     *
     * @param src
     * @param request
     * @param response
     * @throws IOException
     */
    public static void downLoadFile(File src, HttpServletRequest request, HttpServletResponse response) throws IOException {
        // 设置编码格式
        response.setCharacterEncoding(UTF_8.name());

        InputStream is = null;
        OutputStream os = null;
        try {
            //获取长度
            long fSize = src.length();
            response.setContentType("application/x-download");
            String fileName = URLEncoder.encode(src.getName(), UTF_8);
            response.addHeader("Content-Disposition", "attachment;filename=" + fileName);
            //根据前端传来的Range  判断支不支持分片下载
            response.setHeader("Accept-Range", "bytes");
            response.setHeader("fName", fileName);
            //定义断点
            long pos = 0, last = fSize - 1, sum = 0;
            //判断前端需不需要分片下载
            if (null != request.getHeader("Range")) {
                response.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT);
                String numRange = request.getHeader("Range").replaceAll("bytes=", "");
                String[] strRange = numRange.split("-");
                if (strRange.length == 2) {
                    pos = Long.parseLong(strRange[0].trim());
                    last = Long.parseLong(strRange[1].trim());
                    //若结束字节超出文件大小 取文件大小
                    if (last > fSize - 1) {
                        last = fSize - 1;
                    }
                } else {
                    //若只给一个长度  开始位置一直到结束
                    pos = Long.parseLong(numRange.replaceAll("-", "").trim());
                }
            }
            long rangeLength = last - pos + 1;
            String contentRange = "bytes" + pos + "-" + last + "/" + fSize;
            response.setHeader("Content-Range", contentRange);
            os = new BufferedOutputStream(response.getOutputStream());
            is = new BufferedInputStream(new FileInputStream(src));
            // 跳过已读的文件(重点，跳过之前已经读过的文件)
            is.skip(pos);
            byte[] buffer = new byte[1024];
            int lenght = 0;
            //相等证明读完
            while (sum < rangeLength) {
                lenght = is.read(buffer, 0, (rangeLength - sum) <= buffer.length ? (int) (rangeLength - sum) : buffer.length);
                sum = sum + lenght;
                os.write(buffer, 0, lenght);
            }
            log.info("下载完成");
        } finally {
            if (is != null) {
                is.close();
            }
            if (os != null) {
                os.close();
            }
        }
    }
}

